﻿namespace NuGetCop.MSBuild.Tasks
{
    using System;
    using System.Diagnostics;
    using System.Globalization;
    using System.Linq;
    using NuGetCop.MSBuild.Tasks.Foundation;

    internal sealed class NuGetPackageReference : INuGetPackageReference
    {
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private string id;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private string targetFramework;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private string version;

        private bool isReadOnly;

        public string Id
        {
            [DebuggerStepThrough]
            get
            {
                return id;
            }

            set
            {
                EnsureEditable();
                id = value;
            }
        }

        public string TargetFramework
        {
            [DebuggerStepThrough]
            get
            {
                return targetFramework;
            }

            set
            {
                EnsureEditable();
                targetFramework = value;
            }
        }

        public string Version
        {
            [DebuggerStepThrough]
            get
            {
                return version;
            }

            set
            {
                EnsureEditable();
                version = value;
            }
        }

        public void MakeReadOnly()
        {
            isReadOnly = true;
        }

        public bool Equals(INuGetPackageReference other)
        {
            if (other == null)
            {
                return false;
            }

            return
                Id == other.Id &&
                Version == other.Version &&
                TargetFramework == other.TargetFramework;
        }

        public override bool Equals(object obj)
        {
            return Equals(obj as INuGetPackageReference);
        }

        public override int GetHashCode()
        {
            var hash = new[]
                {
                    Id, Version, TargetFramework
                }
                .Aggregate(1, (current, item) => current * 31 + item.Eval(x => x.GetHashCode()));

            return hash;
        }

        public override string ToString()
        {
            return string.Format(
                CultureInfo.InvariantCulture,
                "Id = {0}, Version={1}, TargetFramework={2}",
                Id,
                Version,
                TargetFramework);
        }

        private void EnsureEditable()
        {
            if (isReadOnly)
            {
                throw new InvalidOperationException("It is not allowed to modify this object. It is marked as read-only.");
            }
        }
    }
}